package vista;

import interfasesEdificio.EntrenadorUnidad;
import interfasesUnidades.Entrenable;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;

import javax.swing.DefaultListModel;
import javax.swing.ListSelectionModel;

import unidades.Unidad;

import colaDeProduccion.ColaDeProduccion;
import colaDeProduccion.Producto;

import mapas.Region;
import clasesGenerales.Conjunto;
import control.entrenarUnidad.botonEntrenarListener;
import control.juego.ControladorSeleccion;
import control.ronda.controladorFinTurno;
import edificios.Edificio;

/**
 * @author Grupo 2, Algoritmos y programacion 3, Catedra Fontela<br>1er cuat 2007    
 * <br> Esta clase se encarga de representar la vista para entrenar unidades.
 */

public class VistaEntrenarUnidad extends VentanaConDosListas implements Observer, CerrablePorFinTurno{

	//Modelo
	private Region region;
	private Conjunto UnidadesAEntrenar;
	private Conjunto UnidadesEntrenando;
	
	private static String subtitulo1 = "Unidades a entrenar";
	private static String subtitulo2 = "Unidades entrenando ";
	private static String accion = "Entrenar";
	
	private static VistaEntrenarUnidad Instance = null;
	
	/**
	 * Se encarga de inicializar la vista para generar unidades.
	 * @param titulo Titulo de la ventana
	 */
	private VistaEntrenarUnidad(String titulo){
		//Llamo al constructor del padre
		super(titulo, subtitulo1, subtitulo2, accion);
		
		UnidadesAEntrenar = new Conjunto();
		UnidadesEntrenando = new Conjunto();
		
		//agrego la funcionalidad a los botones
		this.ActivarComportamientoBotonAccion();
		this.ActivarComportamientoBotonSalir();
		
		//agrego la referencia a la instancia
		Instance = this;
		//agrego la instancia como Cerrable al finalizar el turno
		controladorFinTurno.getInstance().agregarVistaCerrable(this);
		this.getLista1().setSelectedIndex(0);
	}
	
	/**
	 * Notifica a la vista de los cambios de seleccion de regiones
	 */
	private void actualizarModelo(){
		String titulo = " - ENTRENAR EN ";
		if (region!=null){
			region.deleteObserver(this);
			borrarObservadoresUnidades(region);
			borrarObservadoresUnidadesEntrenando(region);
		}
		//Conecto con el modelo
		this.region = ControladorSeleccion.GetInstance().getSlot1();
		if (region!=null){
			region.addObserver(this);
			//cargo las unidades a entrenar y las entrenando
			CargarUnidades(getModelo1(), this.region);
			CargarUnidadesEntrenando(getModelo2(), this.region);
			titulo += region.getNombre();
		} else
			titulo += "NINGUNA";
		titulo += " - ";
		this.setTitle(titulo);
		this.update(null,null);
	}
	
	/**
	 * @return Unica intancia de VistaMover
	 */
	public static VistaEntrenarUnidad getInstance(){
		if (Instance == null)
			new VistaEntrenarUnidad(" - ENTRENAR - ");
		//conecto con el modelo
		Instance.actualizarModelo();
		return Instance;
	}
	
	/**
	 * Establece los modos de seleccion de las listas.
	 */
	protected void establecerModosDeSeleccion(){
		getLista1().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		getLista2().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
	}
	
	/**
	 * Se encarga de actualizar la vista, cuando el modelo cambie
	 */
	public void update(Observable arg0, Object arg1) {
		//Remuevo todos los elementos de las listas
		this.getModelo1().removeAllElements();
		this.getModelo2().removeAllElements();
		//Si la region no es nula
		if (region != null){
			//cargo las unidades a entrenar y las entrenando
			CargarUnidades(getModelo1(), this.region);
			CargarUnidadesEntrenando(getModelo2(), this.region);
		}
	}

	/**
	 * Carga las unidades entrenables de una region en un modelo de lista
	 * @param modeloLista Modelo donde cargar las unidades
	 * @param region Region que contiene a las unidades
	 */
	private void CargarUnidades(DefaultListModel modeloLista, Region region){
		//Vacio el conjunto de unidades a entrenar
		UnidadesAEntrenar.vaciar();
		//Obtengo las unidades
		Conjunto unidades = region.getUnidades();
		//Monto un iterador y recorro los elementos
		Iterator iterador = unidades.iterator();
		while (iterador.hasNext()){
			//Obtengo cada unidad y la agrego al modelo de la lista
			Unidad unidad = (Unidad) iterador.next();
			//Si es entrenable la agrego
			if (unidad instanceof Entrenable){
				modeloLista.addElement(unidad);
				UnidadesAEntrenar.agregarElemento(unidad);
				unidad.addObserver(this);
			}
		}
	}
	/**
	 * Carga las unidades que estan entrenando en una region
	 * @param modeloLista modelo de la lista donde cargar las unidades
	 * @param region Region que contiene a las unidades
	 */
	private void CargarUnidadesEntrenando(DefaultListModel modeloLista, Region region){
		try{
			//Vacio el conjunto de unidades entrenando
			UnidadesEntrenando.vaciar();
			//Obtengo todos los edificios de la region
			Conjunto edificios = region.getEdificios();
			//Monto un iterador y recorro los elementos
			Iterator iterador = edificios.iterator();
			while (iterador.hasNext()){
				//Por cada producto, si es entrenador agrego los elementos de su cola de prod
				Edificio edificio = (Edificio) iterador.next();
				if (edificio instanceof EntrenadorUnidad){
					ColaDeProduccion cola = edificio.getColaDeProduccion();
					cola.addObserver(this);
					ArrayList productos = cola.getProductos();
					//Monto otro iterador y recorro los elementos
					Iterator itproductos = productos.iterator();
					while(itproductos.hasNext()){
						//Cargo las unidades entrenando
						Producto producto = (Producto)itproductos.next();
						modeloLista.addElement(producto);
						UnidadesEntrenando.agregarElemento(producto.getContenido());
						producto.addObserver(this);
					}
				}
			}
		} catch (NullPointerException e){}
	}
	
	/**
	 * Saca esta vista como observadora de las unidades en region
	 * @param region Region que contiene a las unidades
	 */
	private void borrarObservadoresUnidades (Region region){
		//Vacio el conjunto de unidades a entrenar
		UnidadesAEntrenar.vaciar();
		//Obtengo las unidades
		Conjunto unidades = region.getUnidades();
		//Monto un iterador y recorro los elementos
		Iterator iterador = unidades.iterator();
		while (iterador.hasNext()){
			//Obtengo cada unidad y la agrego al modelo de la lista
			Unidad unidad = (Unidad) iterador.next();
			//Si es entrenable le saco el observador
			if (unidad instanceof Entrenable){
				UnidadesAEntrenar.agregarElemento(unidad);
				unidad.deleteObserver(this);
			}
		}
	}
	
	/**
	 * Saca esta vista como observadora de las unidades que estan entrenando en la region
	 * @param region Region que contiene a las unidades entrenando
	 */
	private void borrarObservadoresUnidadesEntrenando(Region region){
		try{
			//Vacio el conjunto de unidades entrenando
			UnidadesEntrenando.vaciar();
			//Obtengo todos los edificios de la region
			Conjunto edificios = region.getEdificios();
			//Monto un iterador y recorro los elementos
			Iterator iterador = edificios.iterator();
			while (iterador.hasNext()){
				//Por cada edificio, si es entrenador saco el observador de su cola de prod
				Edificio edificio = (Edificio) iterador.next();
				if (edificio instanceof EntrenadorUnidad){
					ColaDeProduccion cola = edificio.getColaDeProduccion();
					cola.deleteObserver(this);
					ArrayList productos = cola.getProductos();
					//Monto otro iterador y recorro los elementos
					Iterator itproductos = productos.iterator();
					while(itproductos.hasNext()){
						//Saco el observador de las unidades entrenando
						Producto producto = (Producto)itproductos.next();
						producto.deleteObserver(this);
					}
				}
			}
		} catch (NullPointerException e){}
	}
	
	/**
	 * @return La region donde se entrenan unidades
	 */
	public Region getRegion(){
		return this.region;
	}
	/**
	 * @return El conjunto de unidades disponibles para entrenar en la region
	 */
	public Conjunto getUnidadesAEntrenar(){
		return this.UnidadesAEntrenar;
	}
	/**
	 * @return El conjunto de unidades que esta entrenando
	 */
	public Conjunto getUnidadesEntrenando(){
		return this.UnidadesEntrenando;
	}
	/**
	 * Activa el comportamiento del boton accion.
	 * Le asigna la accion de Entrenar Unidad.
	 */
	protected void ActivarComportamientoBotonAccion(){
		this.getBotonAccion().addActionListener(new botonEntrenarListener(this));
	}

	public void CerrarVentana() {
		this.setVisible(false);
	}
}

